/*
 * Copyright (C) 2010 M. Hautle.
 * 
 * This file is part of TrackedBean.
 * 
 * TrackedBean is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * TrackedBean is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with TrackedBean. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.trackedbean.loaders;

import java.util.*;
import ch.trackedbean.loaders.lists.*;
import ch.trackedbean.loaders.objects.*;

/**
 * Strategy for {@link DataManager}.<br>
 * The idea behind this strategy is to give a possibility to intercept/cache/... all business objects requested/mutations by a client.<br>
 * 
 * To register the strategy create simply a service provider file for it:<br>
 * Thus is a <code>META-INF/services/ch.trackedbean.loaders.ILoaderStrategy</code> file containing the fully qualified names of the implementations.<br>
 * <br>
 * See {@link ServiceLoader} for further information about service providing.
 * 
 * @author M. Hautle
 */
public interface ILoaderStrategy {
    /**
     * Load request for a list.<br>
     * The simplest possible implementation just calls {@link IListLoader#load(Class, Object, Map)} with the passed arguments and returns the result.<br>
     * However you may provide a cache the results if (and only if!) {@link IListLoader#isCachable(Class, Object, Map)} returned true for the passed arguments.
     * 
     * @param <T> The type to load
     * @param <D> The discriminator type
     * @param <K> The settings key type
     * @param <V> The settings value type
     * @param loader The loader to use
     * @param type The content type of the list
     * @param subType Additional discriminator specifying the "subtype" to load (may be null)
     * @param settings Optional settings for the load (may be null)
     * @param forceLoad True if the load should be forced ignoring any (possibly) cached entries
     * @return The list for the given key
     * @throws Exception If an error occurred during the load
     */
    <T, D, K, V> List<T> getList(IListLoader<T, D, K, V> loader, Class<T> type, D subType, Map<K, V> settings, boolean forceLoad) throws Exception;

    /**
     * Loads request for a object.<br>
     * The simplest possible implementation just calls {@link IObjectHandler#load(Class, Object)} with the passed arguments and returns the result.<br>
     * However you may provide a cache the results if (and only if!) {@link IObjectHandler#isCachable(Class, Object)} returned true for the passed arguments.
     * 
     * @param <T> The object type
     * @param <K> The key type
     * @param handler The handler to use
     * @param type The type to load
     * @param key The key of the object to load
     * @param forceLoad True if the load should be forced ignoring any (possibly) cached entries
     * @return The object or null if no such object exists
     * @throws Exception If something went wrong during the load
     */
    <T, K> T load(IObjectHandler<T, K> handler, Class<T> type, K key, boolean forceLoad) throws Exception;

    /**
     * Persists the given object.<br>
     * The simplest possible implementation just calls {@link IObjectHandler#persist(Object)} with the passed argument and returns the result.<br>
     * However you may also invalidate/update previously cached entries inside this method.<br>
     * The implementation should inform the concerned {@link IDataListener}s.
     * 
     * @param <T> The object type
     * @param <K> The key type
     * @param handler The handler to use
     * @param value The object to persist
     * @return The persisted object
     * @throws Exception If something went wrong while persisting the object
     */
    <T, K> T persist(IObjectHandler<T, K> handler, T value) throws Exception;

    /**
     * Updates the persisted object with the given one.<br>
     * The simplest possible implementation just calls {@link IObjectHandler#update(Object)} with the passed argument and returns the result.<br>
     * However you may also invalidate/update previously cached entries inside this method.<br>
     * The implementation should inform the concerned {@link IDataListener}s.
     * 
     * @param <T> The object type
     * @param <K> The key type
     * @param handler The handler to use
     * @param value The object to update
     * @return The updated object
     * @throws Exception If something went wrong while updating the object
     */
    <T, K> T update(IObjectHandler<T, K> handler, T value) throws Exception;

    /**
     * Removes the object of the given type with the specified key.<br>
     * The simplest possible implementation just calls {@link IObjectHandler#remove(Class, Object)} with the passed argument and returns the result.<br>
     * However you may also invalidate/update previously cached entries inside this method.<br>
     * The implementation should inform the concerned {@link IDataListener}s.
     * 
     * @param <T> The object type
     * @param <K> The key type
     * @param handler The handler to use
     * @param type The type of the object to remove
     * @param key The key of the object to remove
     * @return True if the object was remove, false if no such object existed
     * @throws Exception If something went wrong while removing the object
     */
    <T, K> boolean remove(IObjectHandler<T, K> handler, Class<T> type, K key) throws Exception;

    /**
     * Fires a changed event for the specified object type description.<br>
     * This is the backing implementation of {@link DataManager#fireObjectsChangedEvent(Class, Object, Map)}.
     * 
     * @param <T> The object type
     * @param <D> The discriminator type
     * @param <K> The key type for the parameter map
     * @param <V> The value type for the parameter map
     * @param type The type of the concerned object
     * @param subType Additional discriminator specifying the "subtype" which is concerned (may be null)
     * @param settings Additional settings for the load (may be null)
     */
    <T, D, K, V> void fireObjectsChangedEvent(Class<T> type, D subType, Map<K, V> settings);

    /**
     * Fires a changed event for the specified object.<br>
     * This is the backing implementation of {@link DataManager#fireObjectChangedEvent(Class, Object)}.
     * 
     * @param <T> The object type
     * @param <K> The key type
     * @param type The type of the object which has changed
     * @param key The key of the object which has changed
     */
    <T, K> void fireObjectChangedEvent(Class<T> type, K key);

    /**
     * Registers the given listener on the specified type.
     * 
     * @param l The listener
     * @param type The concrete type
     */
    void addDataListener(IDataListener l, Class type);

    /**
     * Removes the given listener from the specified type.
     * 
     * @param l The listener
     * @param type The concrete type
     */
    void removeDataListener(IDataListener l, Class type);

    /**
     * Registers the given listener on the specified type and all it's subtypes.
     * 
     * @param l The listener
     * @param type The base type
     */
    void addStructureDataListener(IDataListener l, Class type);

    /**
     * Removes the given listener from the specified type and all it's subtypes.
     * 
     * @param l The listener
     * @param type The base type
     */
    void removeStructureDataListener(IDataListener l, Class type);
}
